/**
 * @abstract 一款前端图片调整工具的jquery插件
 * @author: gx1727@163.com
 * @host: https://gitee.com/gx1727/xximg
 * @version: v1.0
 */
(function ($) {
    $.fn.xximg = function (param1, param2) {
        var cmd = 'init';
        var options = {};
        if (typeof param1 == "object") {
            options = param1;
        } else if (typeof param1 == "string") {
            cmd = param1;
            if (typeof param2 == "object") {
                options = param2;
                options = $.extend({_refresh: true}, options);
            } else if (typeof param2 == 'boolean') {
                options = param2;
            }
        }

        return this.each(function () {
            var $this = $(this);
            var o = handle(cmd, $this, options);

            o.success($this, o);
            //  console.log(o);
        });

        function handle(cmd, $this, options) {
            switch (cmd) {
                case 'init':
                    return init($this, options);
                    break;
                case 'get':
                    break;
                case 'set':
                    var key = $this.attr('_xx_key');
                    var o = $this.data(key);
                    o = $.extend(o, options);
                    $this.data(o.key, o); // 记录数据
                    return o;
                    break;
                case 'refresh':
                    var key = $this.attr('_xx_key');
                    var o = $this.data(key);
                    if (typeof options == 'boolean') { // 当refresh的参数为boolean时，使用当前参数
                        // 当refresh的参数 true 时， 强制刷新
                        // 当refresh的参数 false 时， 判断参数变化，智能刷新
                        options = {src: $this.attr('original_src'), _refresh: options};
                    }
                    o = $.extend(o, options);


                    processor($this, o);

                    return o;
                    break;
            }

        }

        function init($this, options) {
            // 生成key ,保存数据到$.data中
            var o = $.extend(
                {
                    key: 'xximg_' + Math.ceil(Math.random() * 100000) + Math.ceil(Math.random() * 1000000),
                    image: false,
                    canvas: false,
                    ctx: false,
                    src: false,
                    sx: 0, // 原图的裁切原点x
                    sy: 0, // 原图的裁切原点y
                    swidth: 0, // 原图的裁切width
                    sheight: 0, // 原图的裁切height
                    px: 0, // 画板的绘图原点x
                    py: 0, // 画板的绘图原点y
                    pwidth: 0, // 画板的绘图width
                    pheight: 0, // 画板的绘图height
                    _offet_width: 0, // 内置变量，用于记录宽度的偏差
                    _offet_height: 0, // 内置变量，用于记录高度的偏差
                    _refresh: false, // 内置变量，ture:强制刷新 false:判断参数变化，智能刷新

                }, $.fn.xximg.defaults, options);

            var mod = $this.attr('_xx_mod');
            if (mod) {
                o.mod = mod;
            }

            var pos = $this.attr('_xx_pos');
            if (pos) {
                o.pos = parseFloat(pos);
            }

            var autoresize = $this.attr('_xx_autoresize');
            if (autoresize == 'on') {
                o.autoresize = true;
            } else {
                o.autoresize = false;
            }

            processor($this, o);

            if (o.autoresize && !o.resizeEnabled) {
                $(window).resize(function () {
                    $this.xximg('refresh', false);
                })
                o.resizeEnabled = true;
                $this.data(o.key, o); // 记录数据
            }
            return o;
        }

        function processor($this, o) {
            // 获到图片源
            if (!o.src) {
                o.src = $this.attr('src');
            }
            // 创建 canvas DOM 对象
            o.canvas = document.createElement("canvas");
            o.canvas.style.display = "none";
            o.ctx = o.canvas.getContext("2d");  // 获取 canvas的 2d 环境对象,

            o.image = new Image();
            o.image.onload = function () {
                o.img_width = o.image.width;
                o.img_height = o.image.height;

                if (o._refresh) { // 强制刷新
                    // 获到 目标高宽
                    $this.css(o.start);

                    o.width = o.get_width($this, o); // 目标宽
                    o.height = o.get_height($this, o); //  目标高
                } else { // 判断参数变化，智能刷新
                    var w = o.get_width($this, o); // 目标宽
                    var h = o.get_height($this, o); //  目标高
                    if (o.width == w && o.height == h) {
                        return;
                    } else {
                        $this.css(o.start);

                        o.width = w;
                        o.height = h;
                    }
                }

                // 设置画布大小，画布大小即目标的大小
                o.canvas.width = o.width;
                o.canvas.height = o.height;

                // 核心处理计算
                calculate($this, o);

                draw($this, o);

                //
                $this.data(o.key, o); // 记录数据
                $this.attr('_xx_key', o.key);
                $this.attr('original_src', o.src);
                o.src = false;

            };
            o.image.onerror = function (error) {
                o.failed($this, o, error);
            }

            o.image.setAttribute('crossOrigin', 'anonymous');
            o.image.src = o.src;
        }

        /**
         * 计算
         */
        function calculate($this, o) {
            if (o.mod == 'elastic') { // 伸缩
                if ((o.width / o.img_width) <= (o.height / o.img_height)) {
                    // 以目标宽度为准，高度偏移，上下留旁白
                    var h = o.width * o.img_height / o.img_width;
                    o.px = 0;
                    o.py = (o.height - h) / 2;
                    o.pwidth = o.width;
                    o.pheight = h;
                } else {
                    // 以目标高度为准，宽度偏移，左右留旁白
                    var w = o.height * o.img_width / o.img_height;

                    o.px = (o.width - w) / 2;
                    o.py = 0;
                    o.pwidth = w;
                    o.pheight = o.height;
                }
            } else if (o.mod == 'cutting') {//裁切
                if ((o.width / o.img_width) <= (o.height / o.img_height)) {
                    // 以目标高度为准，宽度超出，裁切
                    var w = o.width * o.img_height / o.height;

                    o.px = 0;
                    o.py = 0;
                    o.pwidth = o.width;
                    o.pheight = o.height;

                    // 计算
                    var sx = o.img_width * o.pos - w / 2;
                    if (sx <= 0) {
                        o.sx = 0;
                    } else if (sx + w > o.img_width) {
                        o.sx = o.img_width - w;
                    } else {
                        o.sx = sx;
                    }

                    o.sy = 0;
                    o.swidth = w; // 计算
                    o.sheight = o.img_height;
                } else {
                    // 以目标宽度为准，宽度超出，裁切
                    var h = o.height * o.img_width / o.width;

                    o.px = 0;
                    o.py = 0;
                    o.pwidth = o.width;
                    o.pheight = o.height;

                    o.sx = 0;
                    // 计算
                    var sy = o.img_height * o.pos - h / 2;
                    if (sy <= 0) {
                        o.sy = 0;
                    } else if (sy + h > o.img_height) {
                        o.sy = o.img_height - h;
                    } else {
                        o.sy = sy;
                    }
                    o.swidth = o.img_width;
                    o.sheight = h;// 计算
                }
            }
        }

        /**
         * 画图 并 显示
         * @param $this
         * @param o
         */
        function draw($this, o) {
            // canvas清屏
            o.ctx.clearRect(0, 0, o.canvas.width, o.canvas.height);
            o.ctx.fillStyle = o.backgroundColor;

            o.ctx.fillRect(0, 0, o.canvas.width, o.canvas.height);

            // 将图像绘制到canvas上
            if (o.mod == 'elastic') { // 伸缩
                o.ctx.drawImage(o.image, o.px, o.py, o.pwidth, o.pheight);
            } else if (o.mod == 'cutting') { //裁切
                o.ctx.drawImage(o.image, o.sx, o.sy, o.swidth, o.sheight, o.px, o.py, o.pwidth, o.pheight);
            }

            $this.unbind('load').load(function () {
                if (o._offet_width == 0 && (o.get_width($this, o) - $this.width()) != 0) {
                    o._offet_width = o.get_width($this, o) - $this.width();
                }
                if (o._offet_height == 0 && (o.get_height($this, o) - $this.height()) != 0) {
                    o._offet_height = o.get_height($this, o) - $this.height();
                }
                $this.animate(o.end, o.speed);

                delete o.image;
                delete o.canvas;
                delete o.ctx;
            });
            $this.attr('src', o.canvas.toDataURL());
        }
    }
    $.fn.xximg.defaults = {
        backgroundColor: '#FFFFFF', // 背景色，在有旁边时会体现 透明：rgba(255, 255, 255, 0)
        start: {opacity: 0}, // 开始时显示的透明度
        end: {opacity: 1}, // 结束减肥显示的透明度
        speed: 600, // 完成后的显示速度
        mod: 'cutting', // elastic: 伸缩  cutting: 裁切
        pos: 0.5, // 0-1 之间， 中心点的位置， 当mod为裁切时有效
        src: false, // 图片的源地址
        autoresize: false, // 图片尺寸变化时，自动resize
        resizeEnabled: false, // 自动resize是否已启动
        /**
         * 获到宽度
         * @param $this
         * @param o
         * @returns {*}
         */
        get_width: function ($this, o) {
            var width = $this.attr('_xx_width');
            if (width) { // 有显式设置
                if (width == 'parent') {
                    width = $this.parent().width();
                } else if (width == 'parent.parent') {
                    width = $this.parent().parent().width();
                }
            } else {
                // 没有显式设置时，自动使用自己的宽度
                width = $this.width();
            }
            return parseFloat(width - o._offet_width);
        },

        /**
         * 获到高度
         * @param $this
         * @param o
         * @returns {*}
         */
        get_height: function ($this, o) {
            var height = $this.attr('_xx_height');

            if (height) { // 有显式设置
                if (height == 'parent') {
                    height = $this.parent().height();
                } else if (height == 'parent.parent') {
                    height = $this.parent().parent().height();
                }
            } else {
                // 没有显式设置时，自动使用自己的高度
                height = $this.height();
            }

            return parseFloat(height - o._offet_height);
        },
        /**
         * 成功时回调
         * @param $this
         * @param o
         */
        success: function ($this, o) {
            // console.log('success');
        },
        /**
         * 图片加截失败时回调
         * @param $this
         * @param o
         * @param error
         */
        failed: function ($this, o, error) {
            console.log(error);
        }
    }
})(jQuery);